package com.gz.moreaseManager.config;

import com.gz.moreaseManager.core.base.Constants;
import com.gz.moreaseManager.core.base.RedisSupport;
import com.gz.moreaseManager.core.modal.AjaxResult;
import com.gz.moreaseManager.core.modal.HttpCode;
import com.gz.moreaseManager.utils.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import java.io.PrintWriter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	/**
	 * 需要放行的URL
	 */
	private String[] AUTH_WHITELIST = {"/","/web/**","/ueditor/**","/css/**", "/fonts/**","/config","/pictureViewer/**",
			"/images/**", "/js/**", "/layui/**", "/error/**","/**/find**","/file/**","/upload/**","/favicon.ico"};

	private final RedisSupport redisSupport;
	private final SelfAuthenticationProvider authenticationProvider;

	@Autowired
	public WebSecurityConfig(RedisSupport redisSupport, SelfAuthenticationProvider authenticationProvider) {
		this.redisSupport = redisSupport;
		this.authenticationProvider = authenticationProvider;
	}

	/**
	 * 设置资源验证规则
	 *
	 * @param httpSecurity httpSecurity
	 * @throws Exception 异常
	 */
	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {
		httpSecurity.cors().and().csrf().disable() // 禁用csrf
				// 不需要拦截验证
				.authorizeRequests().antMatchers(HttpMethod.GET, AUTH_WHITELIST).permitAll()
				// 除上面外请求需要鉴权认证
				.anyRequest().authenticated()
				// 登录信息配置
				.and().formLogin().usernameParameter("name").passwordParameter("pwd")
				.loginPage("/login").loginProcessingUrl("/loginService")
				.successHandler(getSuccessHandler()).failureHandler(getFailureHandler()).permitAll()
				// 退出配置
				.and().logout().permitAll().invalidateHttpSession(true).
				deleteCookies("JSESSIONID").logoutSuccessHandler(logoutSuccessHandler())
				.and().exceptionHandling().accessDeniedPage("/error/403");
		// 禁用缓存
		httpSecurity.headers().frameOptions().disable().cacheControl().disable();
	}

	/**
	 * 登录成功处理类
	 *
	 * @return 处理类
	 */
	private AuthenticationSuccessHandler getSuccessHandler() {
		return (request, response, authentication) -> {
			if ("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
				response.setContentType("application/json;charset=utf-8");
				PrintWriter out = response.getWriter();
				out.write(JsonUtil.toJson(AjaxResult.success()));
				out.flush();
				out.close();
			} else {
				response.sendRedirect(request.getContextPath() + "/main");
			}
		};
	}

	/**
	 * 登录失败处理类
	 *
	 * @return 处理类
	 */
	private AuthenticationFailureHandler getFailureHandler() {
		return (request, response, authentication) -> {
			if ("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
				response.setContentType("application/json;charset=utf-8");
				PrintWriter out = response.getWriter();
				String errorStr = authentication.getLocalizedMessage();
				out.write(JsonUtil.toJson(AjaxResult.build(HttpCode.PWD_ERROR, errorStr)));
				out.flush();
				out.close();
			} else {
				response.sendRedirect(request.getContextPath() + "/login");
			}
		};
	}

	@Bean
	public LogoutSuccessHandler logoutSuccessHandler() { //登出处理
		return (request, response, authentication) -> {
			try {
				Integer userId = ((SelfUserDetails) authentication.getPrincipal()).getUserId();
				redisSupport.delete(String.format(Constants.LOGIN_USER_MENUS_KEY, userId, 1));
				redisSupport.delete(String.format(Constants.LOGIN_USER_MENUS_KEY, userId, 2));
				redisSupport.delete(String.format(Constants.LOGIN_USER_MENUS_KEY, userId, null));
			} catch (Exception e) {
				logger.info("LOGOUT EXCEPTION , e : " + e.getMessage());
			}
			response.sendRedirect("/login");
		};
	}

	// 登录验证拦截配置
	protected void configure(AuthenticationManagerBuilder auth) {
		auth.authenticationProvider(authenticationProvider);
	}
}
